/*
 * Copyright (C) 2010 TopCoder Inc., All Rights Reserved.
 */
package com.hercules.xre.protocol.testing.handlers;

import com.topcoder.util.log.Level;
import com.topcoder.util.log.Log;

import java.util.List;
import java.util.ListIterator;

/**
 * Helper class for this component.
 * <p>
 * <b>Thread safety:</b> This class is immutable and so thread safe.
 *
 * @author 7realm
 * @version 1.0
 */
public final class Helper {
    /**
     * This private constructor prevents to create a new instance.
     */
    private Helper() {
        // empty
    }

    /**
     * Checks whether the given {@link Object} is null.
     *
     * @param arg the argument to check
     * @param name the name of the argument to check
     * @throws IllegalArgumentException if the given object is null
     */
    public static void checkNull(Object arg, String name) {
        if (arg == null) {
            throw new IllegalArgumentException("Argument '" + name + "' should not be null.");
        }
    }

    /**
     * Checks whether the given {@link String} is not null and empty(the length of the given string is zero after
     * trimmed).
     *
     * @param arg the String to check
     * @param name the name of the String argument to check
     * @throws IllegalArgumentException if the given string is null or empty
     */
    public static void checkString(String arg, String name) {
        checkNull(arg, name);
        checkOnlyString(arg, name);
    }

    /**
     * Checks whether the given state condition is correct.
     *
     * @param condition expression that represents correct state
     * @param message the error message
     * @throws IllegalStateException if the given condition is false
     */
    public static void checkState(boolean condition, String message) {
        if (!condition) {
            throw new IllegalStateException(message);
        }
    }

    /**
     * Checks if given list in null or contains null items.
     *
     * @param list the list to check
     * @param name the name of list argument
     * @throws IllegalArgumentException if list is null or contains null elements
     */
    static void checkList(List<?> list, String name) {
        checkNull(list, name);
        if (list.contains(null)) {
            throw new IllegalArgumentException("Argument '" + name + "' should not contain null elements.");
        }
    }

    /**
     * Logs method enter and information about parameters. Also checks arguments
     *
     * @param methodName name of entered method
     * @param logger logger used to log information
     * @param params array of method parameters
     * @throws IllegalArgumentException if any argument is invalid
     */
    static void logEnterAndCheck(Log logger, String methodName, Object... params) {
        logEnter(logger, methodName, params);

        // check arguments
        for (int i = 0; i < params.length; i += 2) {
            if (params[i + 1] instanceof List<?>) {
                List<?> list = (List<?>) params[i + 1];
                checkList(list, (String) params[i]);
                for (ListIterator<?> iter = list.listIterator(); iter.hasNext();) {
                    checkOnlyString((String) iter.next(), params[i] + "[" + iter.previousIndex() + "]");
                }
            } else if (params[i + 1] instanceof String) {
                checkString((String) params[i + 1], (String) params[i]);
            } else {
                checkNull(params[i + 1], (String) params[i]);
            }
        }
    }

    /**
     * Logs method enter and information about parameters.
     *
     * @param methodName name of entered method
     * @param logger logger used to log information
     * @param params array of method parameters
     */
    static void logEnter(Log logger, String methodName, Object... params) {
        if (logger == null) {
            return;
        }
        StringBuilder buffer = new StringBuilder("Entering method ").append(methodName).append(", ");
        if (params.length == 0) {
            buffer.append("no input parameters.");
        } else {
            buffer.append("input parameters: ");
            for (int i = 0; i < params.length; i += 2) {
                if (i != 0) {
                    buffer.append(", ");
                }
                buffer.append("[").append(params[i]).append("=").append(params[i + 1]).append("]");
            }
        }
        logger.log(Level.DEBUG, buffer.toString());
    }

    /**
     * Logs method exit and result.
     *
     * @param <T> the type of method result
     * @param logger logger used for logging
     * @param methodName name of exiting method
     * @param result value of method result
     * @return the method result
     */
    static <T> T logExit(Log logger, String methodName, T result) {
        if (logger != null) {
            logger.log(Level.DEBUG, "Exiting method " + methodName + ", result: [" + String.valueOf(result) + "].");
        }
        return result;
    }

    /**
     * Logs method exit and result.
     *
     * @param logger logger used for logging
     * @param methodName name of exiting method
     */
    static void logExit(Log logger, String methodName) {
        if (logger != null) {
            logger.log(Level.DEBUG, "Exiting method " + methodName + ", method return type is void.");
        }
    }

    /**
     * Logs error occurred in method.
     *
     * @param <T> the type of the error
     * @param logger logger used for logging
     * @param message the log message describing error
     * @param e exception that caused error
     * @return the occurred exception
     */
    static <T extends Throwable> T logError(Log logger, String message, T e) {
        if (logger != null) {
            logger.log(Level.ERROR, e, message);
        }
        return e;
    }

    /**
     * Logs {@link IllegalArgumentException}, occurred occurred in method.
     *
     * @param logger logger used for logging
     * @param e the occurred {@link IllegalArgumentException}
     * @return the occurred exception
     */
    static IllegalArgumentException logIAE(Log logger, IllegalArgumentException e) {
        return logError(logger, "Invalid argument is passed.", e);
    }

    /**
     * Logs {@link IllegalStateException}, occurred occurred in method.
     *
     * @param logger logger used for logging
     * @param e the occurred {@link IllegalStateException}
     * @return the occurred exception
     */
    static IllegalStateException logISE(Log logger, IllegalStateException e) {
        return logError(logger, "Invalid state of instance.", e);
    }

    /**
     * Logs message.
     *
     * @param logger the logger to be used
     * @param message the log message
     */
    static void log(Log logger, String message) {
        if (logger != null) {
            logger.log(Level.INFO, message);
        }
    }

    /**
     * Checks if string is empty.
     *
     * @param arg the string argument to check
     * @param name the name of string argument
     * @throws IllegalArgumentException is string is trimmed empty
     */
    private static void checkOnlyString(String arg, String name) {
        if (arg.trim().length() == 0) {
            throw new IllegalArgumentException("Argument '" + name + "' should not be trimmed empty string.");
        }
    }
}